<?php

namespace App\Trip\Train\TrainInfo;

use App\Models\Orders\Repositories\Interfaces\OrderTripInfoInterface;
use App\Models\Train\Stations\Repositories\Interfaces\StationRepositoryInterface;
use App\Models\Train\Stations\TrainStation;
use App\Models\Train\TrainTripInfo\Repositories\Interfaces\TrainTripInfoRepositoryInterface;
use App\Trip\Train\TrainType;
use App\Trip\Traits\TimeTraits\ArriveDateTimeTrait;
use App\Trip\Traits\TimeTraits\DepartDateTimeTrait;
use App\Trip\Traits\TimeTraits\RunTimeTrait;
use Carbon\Carbon;
use Exception;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Facades\Log;

class TrainInfo implements Arrayable, OrderTripInfoInterface
{
    use ArriveDateTimeTrait, RunTimeTrait, DepartDateTimeTrait;

    private string                     $train_code;
    private string                     $from_station_code = '';
    private string                     $to_station_code   = '';
    private string                     $arrive_at; // 到达日期时间  YYYY-mm-dd H:i
    private string                     $depart_at; // 出发日期时间  YYYY-mm-dd H:i
    private StationRepositoryInterface $stationRepo;
    private int                        $day_difference    = 0;
    private int                        $run_time;
    private string                     $checking_port     = '';
    private ?TrainStation              $to_station        = null;
    private ?TrainStation              $from_station      = null;

    public function __construct()
    {
        $this->stationRepo = app(StationRepositoryInterface::class);
    }

    /**
     * @throws Exception
     */
    public function __get(string $name)
    {
        if (isset($this->$name)) {
            return $this->$name;
        }
        throw  new Exception("属性{$name}不存在");
    }


    public function getTrainCode(): string
    {
        return $this->train_code;
    }

    public function setTrainCode(string $train_code): void
    {
        $this->train_code = $train_code;
    }

    public function calcArriveDate(): string
    {
        return Carbon::parse($this->getStartDate())->addDays($this->getDayDifference())->toDateString();
    }

    /**
     * @throws Exception
     */
    public function toArray(): array
    {
        return $this->getTrainInfo();
    }

    /**
     * @throws Exception
     */
    public function getTrainInfo(): array
    {

        $train_type_name = TrainType::getTrainTypeName($this->train_code);
        $trainTripRepo   = app(TrainTripInfoRepositoryInterface::class);
        if ($trainTripInfo = $trainTripRepo->findOneByTrainAndStation(
            $this->train_code,
            $this->from_station_code,
            $this->to_station_code)
        ) {
            $this->setDayDifference($trainTripInfo->getDayDifference());
            $this->setRunTime($trainTripInfo->getRunTime());
            $this->setCheckingPort($trainTripInfo->getCheckingPort());
            !isset($this->arrive_at) && $this->setArriveAt($this->calcArriveAt());
            if ($this->getArriveTime() != $trainTripInfo->getArriveTime()) {
                Log::error("setArriveTime:{$this->getArriveTime()},dbArriveTime:{$trainTripInfo->getArriveTime()} ");
            }
        }
        return [
            'train_code'           => $this->train_code,
            'from_station_code'    => $this->from_station_code,
            'from_station_name'    => $this->getFromName(),
            'from_station_name_uy' => $this->getFromNameUy(),
            'to_station_code'      => $this->to_station_code,
            'to_station_name'      => $this->getToName(),
            'to_station_name_uy'   => $this->getToNameUy(),
            'start_date'           => $this->getStartDate(),
            'arrive_date'          => $this->getArriveDate(),
            'start_time'           => $this->getStartTime(),
            'arrive_time'          => $this->getArriveTime(),
            'checking_port'        => $this->getCheckingPort(),
            'type'                 => [
                'name'    => $train_type_name,
                'name_uy' => TrainType::getTrainTypeNameTranslation($train_type_name, 'uy'),
            ],
            'run_time'             => $this->getRunTime(),
            'day_difference'       => $this->getDayDifference(),
        ];
    }

    public function getCheckingPort(): string
    {
        return $this->checking_port ?? '';
    }

    public function setCheckingPort(string $checking_port): void
    {
        $this->checking_port = $checking_port;
    }

    public function calcArriveAt(): string
    {
        return Carbon::parse($this->getDepartAt())->addMinutes($this->getRunTime())->toDateTimeString();
    }

    public function getFromName(): string
    {
        return $this->from_station()?->getStationName() ?: '';
    }

    public function from_station(): ?TrainStation
    {
        if ($this->from_station) {
            return $this->from_station;
        }
        $this->from_station = $this->stationRepo->findOneByCode($this->from_station_code, true);
        return $this->from_station;
    }

    public function getFromNameUy(): string
    {
        return $this->from_station()?->getStationNameUy() ?: '';
    }

    public function getToName(): string
    {
        return $this->to_station()?->getStationName() ?: '';
    }

    public function to_station(): ?TrainStation
    {
        if ($this->to_station) {
            return $this->to_station;
        }
        $this->to_station = $this->stationRepo->findOneByCode($this->to_station_code, true);
        return $this->to_station;
    }

    // 出发日期

    public function getToNameUy(): string
    {
        return $this->to_station()?->getStationNameUy() ?: '';
    }

    public function getFromCode(): string
    {
        return $this->getFromStationCode();
    }

    public function getFromStationCode(): string
    {
        return $this->from_station_code;
    }

    public function setFromStationCode(string $from_station_code): void
    {
        if (!$this->from_station_code) {
            $this->from_station_code = $from_station_code;
        }
    }

    public function getToCode(): string
    {
        return $this->getToStationCode();
    }

    public function getToStationCode(): string
    {
        return $this->to_station_code;
    }

    public function setToStationCode(string $to_station_code): void
    {
        if (!$this->to_station_code) {
            $this->to_station_code = $to_station_code;
        }
    }

    public function getTripDate(): string
    {
        return $this->getTrainDate();
    }

    public function getTrainDate(): string
    {
        return $this->getStartDate();
    }
}